﻿using ctolua.Models.Enum;
using ctolua.Models.System;
using ctolua.Models.Type;
using ctolua.sys;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
using static ctolua.Data.slk;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace ctolua.Models
{
    /// <summary>
    /// 单位
    /// </summary>
    public class MUnit
    {
        /// <summary>
        /// 单位实体
        /// </summary>
        public Unit unit { get; set; }
        public Dictionary<dynamic, dynamic> data = new Dictionary<dynamic, dynamic>();
        /// <summary>
        /// 单位id
        /// </summary>
        public int id => (int)this.unit.api_get_id();
        public string id_s;
        /// <summary>
        /// 单位编号
        /// </summary>
        public int key => (int)this.unit.api_get_key();
        /// <summary>
        /// 单位位置
        /// </summary>
        public MPoint pos
        {
            get => new MPoint(this.unit.api_get_position());
        }
        /// <summary>
        /// 单位角度
        /// </summary>
        public double angle
        {
            get => this.unit.get_face_angle().@float();
            set
            {
                this.unit.api_set_face_angle(py.Fix32(value), 0);
            }
        }
        /// <summary>
        /// 预设 单位icon图标的图片id
        /// </summary>
        public int? default_icon => game_api.get_icon_id_by_unit_type(this.key);
        /// <summary>
        /// 预设 单位类型的名称
        /// </summary>
        public string default_name => game_api.get_unit_name_by_type(this.key);
        /// <summary>
        /// 预设 单位类型的描述
        /// </summary>
        public string default_desc => game_api.get_unit_desc_by_type(this.key);
        /// <summary>
        /// 是否为商店
        /// </summary>
        public bool shop => (bool)unit.api_is_shop();
        /// <summary>
        /// 单位所属玩家
        /// </summary>
        public Role role
        {
            get => this.unit.api_get_role();
            set => game_api.change_unit_role(this.unit, value);
        }
        public double _x = 0;
        public double x
        {
            get => _x;
            set
            {
                _x = value;
                MPoint new_p = new MPoint(value, this.pos.y, this.pos.z);
                this.unit.api_transmit(new_p.point);
            }
        }
        public double _y = 0;
        public double y
        {
            get => _y;
            set
            {
                _y = value;
                MPoint new_p = new MPoint(this.pos.x, value, this.pos.z);
                this.unit.api_transmit(new_p.point);
            }
        }

        public double _z = 0;
        public double z
        {
            get => _z;
            set
            {
                _z = value;
                this.unit.api_raise_height(py.Fix32(value) , py.Fix32(0));
            }
        }
        /// <summary>
        /// 获取商店页签数量
        /// </summary>
        public int api_get_shop_tab_cnt => (int)this.unit.api_get_shop_tab_cnt();
        /// <summary>
        /// 获取选择圈缩放
        /// </summary>
        public double? get_select_circle_scale => game_api.get_select_circle_scale(this.unit).@float();
        /// <summary>
        /// 单位实体是否存在
        /// </summary>
        public bool is_null => (bool)game_api.unit_is_exist(this.unit);
        /// <summary>
        /// 最近创建单位实体
        /// </summary>
        /// <returns>单位实体</returns>
        public Unit last_unit => game_api.get_last_created_unit();

        public double 碰撞半径 => this.unit.api_get_unit_collision_radius().@float(); 
        /// <summary>
        /// 转对象 带缓存
        /// </summary>
        /// <param name="unit_id">单位ID</param>
        /// <returns></returns>
        public static MUnit obj(int unit_id)
        {
            string unit = py.toString(game_api.get_unit_by_id(unit_id));
            if (unit == null)
            {
                return null;
            }
            MUnit mUnit = SCache.getUnitCache<MUnit>(unit);
            if (mUnit == null)
            {
                mUnit = new MUnit(unit_id);
                SCache.setUnitCache(unit, mUnit);
                return mUnit;
            }
            mUnit._x = mUnit.pos.x;
            mUnit._y = mUnit.pos.y;
            mUnit._z = mUnit.pos.z;
            return mUnit;
        }
        /// <summary>
        /// 转对象 带缓存
        /// </summary>
        /// <param name="u">单位对象</param>
        /// <returns></returns>
        public static MUnit obj(Unit u)
        {

            if (u == null)
            {
                return null;
            }
            string unit = py.toString(u);
            MUnit mUnit = SCache.getUnitCache<MUnit>(unit);
            if (mUnit == null)
            {
                mUnit = new MUnit(u);
                SCache.setUnitCache(unit, mUnit);
                return mUnit;
            }
            mUnit._x = mUnit.pos.x;
            mUnit._y = mUnit.pos.y;
            mUnit._z = mUnit.pos.z;

            return mUnit;
        }
        /// <summary>
        /// 创建单位
        /// </summary>
        /// <param name="key ">  单位编号   </param>
        /// <param name="pos ">  位置   </param>
        /// <param name="angle ">  朝向   </param>
        /// <param name="role ">  所属玩家   </param>
        /// <returns>创建出的单位</returns>
        public static MUnit create(int key, Point pos, double angle, Role role)
        {
            MUnit mUnit = new MUnit(key, pos, angle, role);
            SCache.setUnitCache(py.toString(mUnit.unit), mUnit);
            
            return mUnit;
        }



        public MUnit() { }
        public MUnit(Unit unit) {
            this.unit = unit;
            id_s=py.toString(unit);
        }
        /// <summary>
        /// 根据单位ID获取单位
        /// </summary>
        /// <param name="unit_id">单位id</param>
        public MUnit(int unit_id) {
            this.unit = game_api.get_unit_by_id(unit_id);

            id_s = py.toString(unit);
        }
        /// <summary>
        /// 创建单位
        /// </summary>
        /// <param name="key ">  单位编号   </param>
        /// <param name="pos ">  位置   </param>
        /// <param name="angle ">  朝向   </param>
        /// <param name="role ">  所属玩家   </param>
        /// <returns>创建出的单位</returns>
        public MUnit(int key, Point pos, double angle, Role role) {
            this.unit = game_api.create_unit(key, pos, py.Fix32(angle), role);

            id_s = py.toString(unit);
        }

        /// <summary>
        /// 判断单位是否是幻象单位
        /// </summary>
        public bool? is_unit_illusion => game_api.is_unit_illusion(this.unit);
        /// <summary>
        /// 当前经验值
        /// </summary>
        public int exp => (int)this.unit.api_get_exp(); 
        /// <summary>
        /// 所需经验
        /// </summary>
        public int up_exp => (int)this.unit.api_get_upgrade_exp();

        public void add_exp(int exp) => this.unit.api_add_exp(py.Fix32(exp));
        /// <summary>
        /// 改变单位所属玩家
        /// </summary>
        /// <param name="role ">  所属玩家   </param>
        public void remove_control_unit(Role role) => game_api.change_unit_role(this.unit, role);


        /// <summary>
        /// 给队伍添加单位
        /// </summary>
        /// <param name="team_id ">  队伍编号   </param>
        public void add_unit_to_team(int? team_id) => game_api.add_unit_to_team(this.role, team_id, this.unit);

        /// <summary>
        /// 从队伍中去除单位
        /// </summary>
        /// <param name="team_id ">  队伍编号   </param>
        public void remove_unit_from_team(int? team_id) => game_api.remove_unit_from_team(this.role, team_id, this.unit);
        /// <summary>
        /// 判断单位是否在单位组
        /// </summary>
        /// <param name="group ">  单位组   </param>
        /// <returns>是否在单位组</returns>
        public bool? judge_unit_in_group(UnitGroup group) => game_api.judge_unit_in_group(this.unit, group);
        /// <summary>
        /// 应用伤害
        /// </summary>
        /// <param name="source_unit ">  伤害者   None</param>
        /// <param name="ability ">  来源关联技能   None</param>
        /// <param name="target_unit ">  单位或者物品   None</param>
        /// <param name="damage ">  伤害值   Fix32(0.0)</param>
        /// <param name="damage_type ">  伤害类型   0</param>
        /// <param name="jump_word ">  是否跳字   False</param>
        /// <param name="extra_context ">  extra_data   None</param>
        /// <param name="as_normal_hit ">  视为普攻   False</param>
        /// <param name="critical ">  必定暴击   False</param>
        public void apply_damage(Ability ability, Unit target_unit, Fix32 damage, int? damage_type = 0, bool? jump_word = false, dynamic extra_context = null, bool? as_normal_hit = false, bool? critical = false) => game_api.apply_damage(this.unit, ability, target_unit, damage_type, damage, jump_word, extra_context, as_normal_hit, critical);
        /// <summary>
        /// 删除单位运动器
        /// </summary>
        public void remove_unit_mover() => game_api.remove_unit_mover(this.unit);

        /// <summary>
        /// 打断单位运动器
        /// </summary>
        public void break_unit_mover() => game_api.break_unit_mover(this.unit);

        /// <summary>
        /// 获取单位类型建造资源消耗属性(玩家属性)
        /// </summary>
        /// <param name="unit_key ">  单位类型   </param>
        /// <param name="role_res_key ">  玩家属性   </param>
        /// <returns>玩家属性值</returns>
        public double? get_unit_resource_cost(string player_attr_name) => game_api.get_role_attr_by_unit_type(this.key, player_attr_name);
        /// <summary>
        /// 获取成长属性
        /// </summary>
        /// <param name="attr ">  属性名   </param>
        /// <returns>属性值</returns>
        public double? api_get_attr_growth(string attr) => game_api.api_get_attr_growth(this.key, attr).@float();
        /// <summary>
        /// 设置成长属性
        /// </summary>
        /// <param name="attr ">  属性名   </param>
        /// <param name="value ">  属性值   </param>
        public void api_set_attr_growth(string attr, double value) => game_api.api_set_attr_growth(this.key, attr, py.Fix32(value));
        /// <summary>
        /// 通过技能序列号获取技能
        /// </summary>
        /// <param name="ability_seq ">  技能序列号   </param>
        /// <returns>技能对象</returns>
        public Ability api_get_ability_by_seq(int? ability_seq) => game_api.api_get_ability_by_seq(this.unit, ability_seq);
        /// <summary>
        /// 通过单位编号+技能序列号获取技能
        /// </summary>
        /// <param name="unit_id ">  单位ID   </param>
        /// <param name="ability_seq ">  技能序列号   </param>
        /// <returns>技能对象</returns>
        public static Ability api_get_ability_by_unit_and_seq(int? unit_id, int? ability_seq) => game_api.api_get_ability_by_unit_and_seq(unit_id, ability_seq);
        /// <summary>
        /// 启动行为树
        /// </summary>
        /// <param name="tree_name ">  行为树名称   </param>
        /// <param name="tree_args ">  行为树参数   </param>
        public void assign_behavior_tree(string tree_name, Dict tree_args) => game_api.assign_behavior_tree(this.unit, tree_name, tree_args);
        /// <summary>
        /// 停止一棵行为树
        /// </summary>
        /// <param name="tree_name ">  行为树名称   </param>
        public void stop_behavior_tree(string tree_name) => game_api.stop_behavior_tree(this.unit, tree_name);
        /// <summary>
        /// 停止所有行为树
        /// </summary>
        public void stop_all_behavior_tree() => game_api.stop_all_behavior_tree(this.unit);
        /// <summary>
        /// 运行一次行为树
        /// </summary>
        /// <param name="tree_name ">  行为树名称   </param>
        /// <param name="tree_args ">  行为树参数   </param>
        public void run_behavior_tree_once(string tree_name, Dict tree_args) => game_api.run_behavior_tree_once(this.unit, tree_name, tree_args);
        /// <summary>
        /// 判断单位敌对关系
        /// </summary>
        /// <param name="unit2 ">  单位   </param>
        /// <returns>是否敌对</returns>
        public bool is_enemy(Unit unit2) => (bool)game_api.is_enemy(this.unit, unit2);
        /// <summary>
        /// 判断单位敌对关系
        /// </summary>
        /// <param name="unit2 ">  单位   </param>
        /// <returns>是否敌对</returns>
        public bool is_ally(Unit unit2) => (bool)game_api.is_ally(this.unit, unit2);
        
        /// <summary>
        /// 玩家或单位是否拥有单位的可见性
        /// </summary>
        /// <param name="role_or_unit ">  玩家   </param>
        /// <returns>是否可见</returns>
        public bool? get_visibility_of_unit(Role role_or_unit) => game_api.get_visibility_of_unit(role_or_unit, this.unit);

        /// <summary>
        /// 单位身上的魔法效果
        /// </summary>
        /// <returns></returns>
        public List<string> get_modifier()
        {
            List<string> lua_table = new List<string>();
            var py_list = this.unit.api_get_all_modifiers();
            for (int i = 1; i < py.python_len(py_list) - 1; i++)
            {
                lua_table.Add(py.python_index(py_list, i));
            }
            return lua_table;
        }
        /// <summary>
        /// 根据索引获取技能
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public Ability api_get_ability(int index)
        {
            int type = (int)TAbilityType.通用;
            if (this.unit.api_get_type() == (int)TUnitCategory.英雄)
            {
                type = (int)TAbilityType.英雄;
            }
            return this.unit.api_get_ability(type, index);
        }
        /// <summary>
        /// 单位添加技能
        /// </summary>
        /// <param name="ability_id"> 技能编号 </param>
        /// <returns>技能</returns>
        public Ability api_add_ability(int ability_id)
        {
            int type = (int)TAbilityType.通用;
            Ability a = null;
            if (unit.api_get_type() == (int)TUnitCategory.英雄)
            {
                type = (int)TAbilityType.英雄;
            }
            for (int i = 1; i <= 16; i++)
            {
                var sk = unit.api_get_ability(type, i);
                if (sk != null)
                {
                    a = unit.api_add_ability(type, ability_id, i, 1);
                    break;
                }
            }
            return a;
        }
        /// <summary>
        /// 播放动画
        /// </summary>
        /// <param name="name"> 动画名称 </param>
        /// <param name="rate"> 播放倍率 </param>
        /// <param name="init_time"> 开始时间(s) </param>
        /// <param name="end_time"> 结束时间(s)，正数 -1 表示不结束 </param>
        /// <param name="loop"> 是否循环 </param>
        /// <param name="return_idle"> 播放结束后是否恢复idle </param>
        /// <returns></returns>
        public void api_play_animation(string name, double? rate=1, double? init_time=0, double? end_time=-1, bool loop=false, bool return_idle=false)
        {
            this.unit.api_play_animation( name,  rate,  init_time, end_time,  loop,  return_idle);
        }
        /// <summary>
        /// 应用伤害
        /// </summary>
        /// <param name="ability"> 来源关联技能 </param>
        /// <param name="target_unit"> 受伤单位 </param>
        /// <param name="damage_type"> 伤害类型 </param>
        /// <param name="damage"> 伤害值 </param>
        /// <param name="jump_word"> 是否跳字 </param>
        /// <param name="as_normal_hit"> 视为普攻 </param>
        /// <param name="critical"> 必定暴击 </param>
        /// <returns></returns>
        public void 造成伤害( Unit target_unit,  double damage, EDMGType damage_type, bool? jump_word=true,  bool? as_normal_hit=false, bool? critical=false, Ability ability = null)
        {
            game_api.apply_damage( this.unit,  ability,  target_unit,  (int)damage_type, py.Fix32(damage) ,  jump_word,  null,  as_normal_hit,  critical);
        }
        /// <summary>
        /// 获取单位商店物品商品库存
        /// </summary>
        /// <param name="tab_idx"> 页签id </param>
        /// <param name="item_no"> 物品编号 </param>
        /// <returns>商品库存</returns>
        public int api_get_shop_item_stock(int? tab_idx, int? item_no)
        {
            return (int)this.unit.api_get_shop_item_stock( tab_idx,  item_no);
        }
        /// <summary>
        /// 获得出售商品列表
        /// </summary>
        /// <param name="tab_index">商店标签页</param>
        /// <returns></returns>
        public List<MItemKey> get_shop_item_list(int tab_index)
        {
            List<MItemKey> lua_table = new List<MItemKey>();
            var py_list = this.unit.api_get_shop_item_list(tab_index);
            for (int i = 0; i < py.python_len(py_list); i++)
            {
                MItemKey item = new MItemKey((int)py.python_index(py_list,i));
                lua_table.Add(item);
            }

            return lua_table;
        }
    }
}
